const simpleGit = require('simple-git');
const chalk = require('chalk');
const fs = require('fs-extra');
const path = require('path');
const moment = require('moment');
const os = require('os');

const cwd = process.cwd();
const git = simpleGit(cwd);

/**
 * 
 * @param {*} packageName The package name
 * @param {*} content The old changelog content
 * @param {*} version The current version for package
 * @param {*} newLogs The new found commit log
 * @returns 
 */
const getNewChangeLog = (packageName, content, version, newLogs) => {
  console.log(
    chalk.blue(`[update-changelog] info: start to find ${packageName} new logs for v${version}.`)
  );
  const lines = content.split(os.EOL);
  const versionPattern = /^## \d+\.\d+\.\d+/;
  let versionExisted = false;
  let start = 0; // first meet "## x.x.x"
  let end = 0; // next meet "## x.x.x"
  for (let i = 0; i < lines.length; i++) {
    const line = lines[i];
    if (versionPattern.test(line)) {
      if (!start) {
        start = i;
        if (line.startsWith(`## ${version} (`)) {
          versionExisted = true;
        }
      } else {
        end = i;
        break;
      }
    }
  }

  end = end || lines.length;

  const latestChangelogs = lines.slice(start, end)

  const newItems = [];
  newItems.push('');
  newItems.push(`## ${version} (${moment().format('YYYY-MM-DD')})`);
  newItems.push('');
  let hasNewLog = false;
  for (let i in newLogs) {
    if (!latestChangelogs.includes(newLogs[i].trim())) {
      newItems.push(`${newLogs[i]}`);
      hasNewLog = true;
    } else {
      break;
    }
  }
  newItems.push('');

  if (!versionExisted) {
    if (!hasNewLog) {
      console.log(
        chalk.red(`[update-changelog] minor: ${packageName} found empty updates for ${version}.`)
      );
      console.log(
        chalk.red(`[update-changelog] minor: make sure you already need change package version for ${packageName}?`)
      );
    }
    lines.splice(start - 1, 0, ...newItems);
    console.log(
      chalk.green(`[update-changelog] info: ${packageName} changelogs updated successfully.`)
    );
  } else {
    console.log(
      chalk.blue(`[update-changelog] info: skipped, since ${packageName} changelogs for v${version} already existed.`)
    );
  }
  return lines.join(os.EOL);
};

/**
 * Write change log to sub package folder, according the sub folder your given since last version.
 * @param {*} packageName The package name
 * @param {*} baseDir The sub package root base dir
 */
async function writeLogs(packageName, baseDir, watchDir) {
  const logs = await git.log({ file: watchDir });
  const newLogs = [];
  for (let i = 0; i < logs.all.length; i += 1) {
    const { message, hash } = logs.all[i];
    let prID = null;
    if (/^Merged PR \d+/.test(message)) {
      const match = message.match(/\d+/g);
      prID = match.length && match[0];
      const text = `* ${message} [#${prID}](https://dev.azure.com/hexagonmi/MI-Genesis/_git/GenesisUILib/pullrequest/${prID})`;
      newLogs.push(text);
    } else {
      const text = `* ${message} [#${hash.substr(0, 6)}](https://dev.azure.com/hexagonmi/MI-Genesis/_git/GenesisUILib/commit/${hash})`;
      newLogs.push(text);
    }
  }
  const changeLogContent = fs
    .readFileSync(path.join(__dirname, '..', baseDir, 'CHANGELOG.md'))
    .toString();
  const packageJson = require(path.join(__dirname, '..', baseDir, 'package.json'));
  const packageVersion = packageJson.version;
  const newChangeLogContent = getNewChangeLog(
    packageName,
    changeLogContent,
    packageVersion,
    newLogs
  );
  fs.writeFileSync(path.join(__dirname, '..', baseDir, 'CHANGELOG.md'), newChangeLogContent);
}

async function main() {
  await writeLogs(
    '@joseph/base',
    'packages/joseph-base',
    'packages/joseph-base/src'
  );
  await writeLogs(
    '@joseph/components',
    'packages/joseph-composite',
    'packages/joseph-composite/src'
  );
  await writeLogs(
    '@joseph/theme',
    'packages/joseph-theme',
    'packages/joseph-theme'
  );
}

main();
